require 'classes'
require 'debugging'
require 'threads'

local s = nil
local channel = nil

local function create_scheduler()
    s = Scheduler:create()
    return true
end

local function create_channels()
    channel = Channel:create()
    return true
end

local function send_messages()

    local producer = Object:create()
    local consumer = Object:create()
    
    local messages_sent, messages_received = 0,0
    
    local messages_expected = 3

    function consumer:main()
        while (true) do
            local message = channel:receive()
            --print("Received: " .. message)
            if (message == "terminate") then
                --print("Time to die")
                return
            end
            messages_received = messages_received + 1
        end
    end

    function producer:main()
        while (messages_sent < messages_expected) do
            channel:send("Message " .. messages_sent + 1)
            messages_sent = messages_sent + 1
        end
        channel:send("terminate")
    end
    
    s:addTask(producer)
    s:addTask(consumer)
    
    s:start()

    return (messages_received == messages_expected)
end

local function sleep_until_woken()
	local sleeper = Tasklet:create()
	local waker = Tasklet:create()
	local looper = Tasklet:create()
	
	local sleepTime = 1
	local subSleepTime = sleepTime / 4
	local subSleeps = 0
	
	local all_done = false
	
	function sleeper:main()
	    -- sleep until we get a message on the channel
	    print("Received: \"" .. channel:receive() .. "\"")
	    all_done = true
	end
	
	function waker:main()
	    -- pause 2 seconds and then wake the waker
	    self:sleep(sleepTime)
	    --pause()
	    channel:send('wake up!')
	end
	
	function looper:main()
	    while (all_done == false) do
	        print("Looper is looping")
    	    subSleeps = subSleeps + 1
    	    self:sleep(subSleepTime)
    	end
    end
	
	s:addTask(sleeper)
    s:addTask(waker)
    s:addTask(looper)
    
    s:start()
    
    assert(subSleeps == 4)
    
    return true
	
end

if tests == nil then tests = {} end

tests.threads = {
    send_messages = {
        description = "Creates two objects that talk to each other",
        test = send_messages,
        prerequisites = {"create_scheduler", "create_channels"}
    },
    
    create_scheduler = {
        description = "Creates a tasklet scheduler",
        test = create_scheduler,
        prerequisites = {}
    }, 
    
    create_channels = {
        description = "Creates a channel for tasklets to talk to",
        test = create_channels,
        prerequisites = {}
    },
    
    sleep_until_woken = {
        description = "Make two threads, one that sleeps and one that wakes it after 2 seconds",
        test = sleep_until_woken,
        prerequisites = {"send_messages"}
    },
}
